package cau.se.project.view;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import swing2swt.layout.BorderLayout;
import cau.se.project.CLSXFile;
import cau.se.project.DSMFile;
import cau.se.project.data.CLSXTreeModel;
import cau.se.project.data.method.GroupControl;
import cau.se.project.data.method.RowControl;
import cau.se.project.inspector.DependencyInspector;
import cau.se.project.method.CLSXControl;
import cau.se.project.view.method.DSMChangeListener;

public class MainFrame implements DSMChangeListener {

	protected Shell shell;
	protected Display display;
	private CLSXControl clsx = new CLSXTreeModel();
	private DSMFile dsmFile = new DSMFile();
	private CLSXFile clsxFile = new CLSXFile(clsx.getDSM());
	private DSMTableView tableView;
	private CLSXTreeView treeView;
	private List<RowControl> arrayList = new ArrayList<>();
	private boolean dsmChanged = false;
	private boolean clsxChanged = false;
	
	private ToolItem tltmLoadClu;
	private MenuItem fileLoadClustering;

	private static final String WINDOW_NAME = new String(
			"Dependency Editor - 2012 SE Project");

	/**
	 * Launch the application.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		MainFrame window = new MainFrame();
		window.open();
	}

	/**
	 * Open the window.
	 */
	public void open() {
		final Image mainIcon = new Image(display, getClass().getResourceAsStream(IconImage.mainIcon));
		
		display = Display.getDefault();
		shell = new Shell();
		
		// Image of Title
		shell.setImage(mainIcon);
		
		// Toolbar area under the Menu Bar
		createContents();
		
		// Menu bar area
		menuBar();
		
		// sashform in the Toolbar area
		sash();
		
		// window initialization
		shell.open();
		shell.setLocation(260, 100);
		shell.layout();
		
		// Exit Event
		shell.addListener(SWT.Close, new Listener() {

			@Override
			public void handleEvent(Event e) {
				if (checkCLSXChange() == false || checkDSMChange() == false) {
					e.doit = false;
					return;
				}
			}
		});
		
		// DSM Initialize
		newDSM();
		
		// Refresh
		refresh();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
	}

	/**
	 * Create contents of the window.
	 */
	protected void createContents() {
		shell.setSize(840, 538);
		shell.setLayout(new BorderLayout(0, 0));

		Composite leftPanelMenu = new Composite(shell, SWT.NONE);
		leftPanelMenu.setLayoutData(BorderLayout.NORTH);

		Label label = new Label(leftPanelMenu, SWT.SEPARATOR | SWT.HORIZONTAL);
		label.setBounds(0, 25, 2048, 2);

		ToolBar toolBar = new ToolBar(leftPanelMenu, SWT.FLAT | SWT.RIGHT);
		toolBar.setBounds(0, 0, 457, 28);

		// Image loading for inserting to icon 
		final Image saveClsxIcon = new Image(display, getClass().getResourceAsStream(IconImage.saveClsxIcon));
		final Image saveClsxAsIcon = new Image(display, getClass().getResourceAsStream(IconImage.saveClsxAsIcon));
		final Image openDSMIcon = new Image(display, getClass().getResourceAsStream(IconImage.openDsmIcon));
		final Image redrawIcon = new Image(display, getClass().getResourceAsStream(IconImage.redrawIcon));
		final Image newClsxIcon = new Image(display, getClass().getResourceAsStream(IconImage.newClsxIcon));
		final Image openClsxIcon = new Image(display, getClass().getResourceAsStream(IconImage.openClsxIcon));

		// Open DSM Icon
		ToolItem tltmOpenDsm = new ToolItem(toolBar, SWT.NONE);
		tltmOpenDsm.setImage(openDSMIcon);
		tltmOpenDsm.addSelectionListener(new OpenFileListener(1));
		tltmOpenDsm.setToolTipText("Open DSM");

		// Redraw Icon
		ToolItem tltmRedraw = new ToolItem(toolBar, SWT.NONE);
		tltmRedraw.setImage(redrawIcon);
		tltmRedraw.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				refresh();
				super.widgetSelected(arg0);
			}
		});
		tltmRedraw.setToolTipText("Redraw");

		new ToolItem(toolBar, SWT.SEPARATOR);

		// New Clustering Icon
		ToolItem tltmNewClu = new ToolItem(toolBar, SWT.NONE);
		tltmNewClu.setImage(newClsxIcon);
		tltmNewClu.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				newCLSX();
				super.widgetSelected(arg0);
			}
		});
		tltmNewClu.setToolTipText("New Clustering");

		// Load Clustering Icon
		tltmLoadClu = new ToolItem(toolBar, SWT.NONE);
		tltmLoadClu.setImage(openClsxIcon);
		tltmLoadClu.addSelectionListener(new OpenFileListener(0));
		tltmLoadClu.setToolTipText("Load Clustering");

		// Save Clustering Icon
		ToolItem tltmSaveClustering = new ToolItem(toolBar, SWT.NONE);
		tltmSaveClustering.setImage(saveClsxIcon);
		tltmSaveClustering.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				saveCLSX();
				super.widgetSelected(e);
			}
		});
		tltmSaveClustering.setToolTipText("Save Clustering");

		// Save Clustering As Icon
		ToolItem tltmSaveClusteringAs = new ToolItem(toolBar, SWT.NONE);
		tltmSaveClusteringAs.setImage(saveClsxAsIcon);
		tltmSaveClusteringAs.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				saveCLSX_as();
				super.widgetSelected(e);
			}
		});
		tltmSaveClusteringAs.setToolTipText("Save Clustering As");
	}

	// Menu Bar
	protected void menuBar() {

		Menu menu = new Menu(shell, SWT.BAR);
		shell.setMenuBar(menu);

		// Image loading for inserting to icon 
		final Image newDsmIcon = new Image(display, getClass().getResourceAsStream(IconImage.newDsmIcon));
		final Image newClsxIcon = new Image(display, getClass().getResourceAsStream(IconImage.newClsxIcon));
		final Image openDsmIcon = new Image(display, getClass().getResourceAsStream(IconImage.openDsmIcon));
		final Image openClsxIcon = new Image(display, getClass().getResourceAsStream(IconImage.openClsxIcon));
		final Image saveClsxIcon = new Image(display, getClass().getResourceAsStream(IconImage.saveClsxIcon));
		final Image saveClsxAsIcon = new Image(display, getClass().getResourceAsStream(IconImage.saveClsxAsIcon));
		final Image redrawIcon = new Image(display, getClass().getResourceAsStream(IconImage.redrawIcon));
		final Image exitIcon = new Image(display, getClass().getResourceAsStream(IconImage.exitIcon));
		final Image aboutIcon = new Image(display, getClass().getResourceAsStream(IconImage.aboutIcon));
		final Image partitionIcon = new Image(display, getClass().getResourceAsStream(IconImage.partitionIcon));
		final Image analyzeIcon = new Image(display, getClass().getResourceAsStream(IconImage.analyzeIcon));

		// File Menu
		MenuItem fileMenuHeader = new MenuItem(menu, SWT.CASCADE);
		fileMenuHeader.setText("&File");

		Menu fileMenu = new Menu(shell, SWT.DROP_DOWN);
		fileMenuHeader.setMenu(fileMenu);

		// New DSM
		MenuItem fileNewDSMItem = new MenuItem(fileMenu, SWT.PUSH);
		fileNewDSMItem.setImage(newDsmIcon);
		fileNewDSMItem.setText("&New DSM			Ctrl + N");
		fileNewDSMItem.setAccelerator(SWT.CTRL+'N');
		fileNewDSMItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				newDSM();
				refreshTitle();
				super.widgetSelected(e);
			}
		});

		// New Clustering
		MenuItem fileNewClustering = new MenuItem(fileMenu, SWT.NONE);
		fileNewClustering.setImage(newClsxIcon);
		fileNewClustering.setText("New Clustering");
		fileNewClustering.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				newCLSX();
				refreshTitle();
				super.widgetSelected(e);
			}
		});

		// Separating Menu area
		new MenuItem(fileMenu, SWT.SEPARATOR);

		// Open DSM
		MenuItem fileOpenDSMItem = new MenuItem(fileMenu, SWT.PUSH);
		fileOpenDSMItem.setImage(openDsmIcon);
		fileOpenDSMItem.setText("&Open DSM				Ctrl + O");
		fileOpenDSMItem.setAccelerator(SWT.CTRL+'O');
		fileOpenDSMItem.addSelectionListener(new OpenFileListener(1));

		// Save DSM
		MenuItem fileSaveDSMItem = new MenuItem(fileMenu, SWT.PUSH);
		fileSaveDSMItem.setImage(saveClsxIcon);
		fileSaveDSMItem.setText("&Save DSM				Ctrl + S");
		fileSaveDSMItem.setAccelerator(SWT.CTRL+'S');
		fileSaveDSMItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				saveDSM();
				super.widgetSelected(e);
			}
		});

		// Save DSM As
		MenuItem fileSaveDsmAs = new MenuItem(fileMenu, SWT.NONE);
		fileSaveDsmAs.setImage(saveClsxAsIcon);
		fileSaveDsmAs.setText("Save DSM As");
		fileSaveDsmAs.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				saveDSM_as();
				super.widgetSelected(e);
			}
		});

		// Separating Menu area
		new MenuItem(fileMenu, SWT.SEPARATOR);

		// Load Clustering
		fileLoadClustering = new MenuItem(fileMenu, SWT.NONE);
		fileLoadClustering.setImage(openClsxIcon);
		fileLoadClustering.setText("&Load Clustering			Ctrl + L");
		fileLoadClustering.setAccelerator(SWT.F5);
		fileLoadClustering.addSelectionListener(new OpenFileListener(0));

		// Save Clustering
		MenuItem fileSaveClustering = new MenuItem(fileMenu, SWT.NONE);
		fileSaveClustering.setImage(saveClsxIcon);
		fileSaveClustering.setText("Save Clustering		Ctrl + Shift + S");
		fileSaveClustering.setAccelerator(SWT.CTRL + SWT.SHIFT + 'S');
		fileSaveClustering.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				saveCLSX();
				super.widgetSelected(arg0);
			}
		});

		// Save Clustering As
		MenuItem fileSaveClusteringAs = new MenuItem(fileMenu, SWT.NONE);
		fileSaveClusteringAs.setImage(saveClsxAsIcon);
		fileSaveClusteringAs.setText("Save Clustering As");
		fileSaveClusteringAs.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				saveCLSX_as();
				super.widgetSelected(arg0);
			}
		});
		
		// Separating Menu area
		new MenuItem(fileMenu, SWT.SEPARATOR);

		// Partitioning
		MenuItem partition = new MenuItem(fileMenu, SWT.NONE);
		partition.setImage(partitionIcon);
		partition.setText("Partitioning");
		partition.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				if (checkCLSXChange() == false)
					return;

				clsxChanged = false;
				newCLSX();
				clsx.doPartition();
				dsmChanged = true;
				onCLSXChanged();
				refresh();
			}
		});

		// Auto analyze .class files
		MenuItem autoAnalyze = new MenuItem(fileMenu, SWT.NONE);
		autoAnalyze.setImage(analyzeIcon);
		autoAnalyze.setText("Auto Analyze .class Files");
		autoAnalyze.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				DependencyInspector inspector = new DependencyInspector(shell,
						display);
				if (inspector.addFilesFromChooser(null)) {
					newDSM();
					clsx = inspector.makeTree();
					refresh();
				}
				super.widgetSelected(arg0);
			}
		});

		// Separating Menu area
		new MenuItem(fileMenu, SWT.SEPARATOR);

		// Exit
		MenuItem fileExitItem = new MenuItem(fileMenu, SWT.PUSH);
		fileExitItem.setImage(exitIcon);
		fileExitItem.setText("E&xit				Ctrl + X");
		fileExitItem.setAccelerator(SWT.CTRL+'X');
		//fileExitItem.setAccelerator(SWT.ALT+"F4");

		fileExitItem.addSelectionListener(new ExitItemListener(shell));

		// View Menu
		MenuItem mntmView = new MenuItem(menu, SWT.CASCADE);
		mntmView.setText("&View");

		Menu viewMenu = new Menu(mntmView);
		mntmView.setMenu(viewMenu);

		// Redraw
		MenuItem mntmRedraw = new MenuItem(viewMenu, SWT.NONE);
		mntmRedraw.setImage(redrawIcon);
		mntmRedraw.setText("&Redraw				Ctrl + R");
		mntmRedraw.setAccelerator(SWT.CTRL+'R');
		mntmRedraw.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				refresh();
				super.widgetSelected(arg0);
			}
		});

		// Separating Toolbar area
		new MenuItem(viewMenu, SWT.SEPARATOR);

		// Show Row Labels
		MenuItem mntmShowRowLabels = new MenuItem(viewMenu, SWT.CHECK);
		mntmShowRowLabels.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				MenuItem item = (MenuItem) e.widget;
				tableView.setShowLabel(item.getSelection());
				refresh();
				super.widgetSelected(e);
			}
		});
		mntmShowRowLabels.setSelection(true);
		mntmShowRowLabels.setText("Show Row & Labels");

		// Help Menu
		MenuItem mntmHelp = new MenuItem(menu, SWT.CASCADE);
		mntmHelp.setText("Help");

		Menu helpMenu = new Menu(mntmHelp);
		mntmHelp.setMenu(helpMenu);

		// About
		MenuItem mntmAbout = new MenuItem(helpMenu, SWT.NONE);
		mntmAbout.setImage(aboutIcon);
		mntmAbout.setText("About");

		mntmAbout.addSelectionListener(new AboutListener());
	}

	// Sashform area
	protected void sash() {
		Composite treeMatrix = new Composite(shell, SWT.NONE);
		treeMatrix.setLayoutData(BorderLayout.CENTER);
		treeMatrix.setLayout(new FillLayout(SWT.HORIZONTAL));

		// Sashform declared by two area
		final SashForm sf = new SashForm(treeMatrix, SWT.BORDER);
		sf.setSashWidth(2);

		Composite composite_1 = new Composite(sf, SWT.NONE);
		composite_1.setLayout(new GridLayout(1, false));

		// image loading for inserting to icon
		final Image expandIcon = new Image(display, getClass().getResourceAsStream(IconImage.expandIcon));
		final Image collapseIcon = new Image(display, getClass().getResourceAsStream(IconImage.collapseIcon));
		final Image groupIcon = new Image(display, getClass().getResourceAsStream(IconImage.groupIcon));
		final Image ungroupIcon = new Image(display, getClass().getResourceAsStream(IconImage.ungroupIcon));
		final Image renameIcon = new Image(display, getClass().getResourceAsStream(IconImage.renameIcon));
		final Image changeRowIcon = new Image(display, getClass().getResourceAsStream(IconImage.changeRowIcon));
		final Image sortIcon = new Image(display, getClass().getResourceAsStream(IconImage.sortIcon));
		final Image moveUpIcon = new Image(display, getClass().getResourceAsStream(IconImage.upIcon));
		final Image moveDownIcon = new Image(display, getClass().getResourceAsStream(IconImage.downIcon));
		final Image deleteIcon = new Image(display, getClass().getResourceAsStream(IconImage.deleteIcon));

		// Declare Toolbar
		ToolBar toolBar = new ToolBar(composite_1, SWT.FLAT | SWT.RIGHT);

		// Expand All Icon
		ToolItem expandAll = new ToolItem(toolBar, SWT.NONE);
		expandAll.setImage(expandIcon);
		expandAll.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				treeView.expandAll();
				super.widgetSelected(arg0);
			}
		});
		expandAll.setToolTipText("Expand All");

		// Collapse All Icon
		ToolItem collapseAll = new ToolItem(toolBar, SWT.NONE);
		collapseAll.setImage(collapseIcon);
		collapseAll.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				treeView.collapseAll();
				super.widgetSelected(arg0);
			}
		});
		collapseAll.setToolTipText("Collapse All");

		// Separating Toolbar area
		new ToolItem(toolBar, SWT.SEPARATOR);

		// Group Icon
		ToolItem groupItem = new ToolItem(toolBar, SWT.NONE);
		groupItem.setImage(groupIcon);
		groupItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				makeGroup();
				super.widgetSelected(e);
			}
		});
		groupItem.setToolTipText("Group");

		// Ungroup Icon
		ToolItem ungroupItem = new ToolItem(toolBar, SWT.NONE);
		ungroupItem.setImage(ungroupIcon);
		ungroupItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				doUngroup();
				super.widgetSelected(e);
			}
		});
		ungroupItem.setToolTipText("Ungroup");

		// Separating Toolbar area
		new ToolItem(toolBar, SWT.SEPARATOR);

		// Rename Icon
		ToolItem renameItem = new ToolItem(toolBar, SWT.NONE);
		renameItem.setImage(renameIcon);
		renameItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				rename();
				super.widgetSelected(e);
			}
		});
		renameItem.setToolTipText("Rename");

		// Change Row Icon
		ToolItem makeRow = new ToolItem(toolBar, SWT.NONE);
		makeRow.setImage(changeRowIcon);
		makeRow.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				addRow();
				super.widgetSelected(e);
			}
		});
		makeRow.setToolTipText("Add Row");
		
		ToolItem toolItem = new ToolItem(toolBar, SWT.SEPARATOR);
		toolItem.setToolTipText("");
		
		// Sort Icon
		ToolItem sortItem = new ToolItem(toolBar, SWT.NONE);
		sortItem.setToolTipText("Sort");
		sortItem.setImage(sortIcon);
		sortItem.addSelectionListener(new SelectionAdapter(){
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				doSort();
			}
		});

		// Separating Toolbar area
		new ToolItem(toolBar, SWT.SEPARATOR);

		// Move Up Icon
		ToolItem moveUp = new ToolItem(toolBar, SWT.NONE);
		moveUp.setImage(moveUpIcon);
		moveUp.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				try {
					RowControl[] rows = treeView.getSelectedItems();
					if (rows.length == 0)
						throw new Exception("적어도 하나의 원소를 선택하세요");

					int index = -1;
					RowControl parent = (RowControl) rows[0].getParent();
					if (parent == null)
						return;

					for (int i = 0; i < rows.length; i++) {
						if (parent != rows[i].getParent()) {
							throw new Exception("부모가 같은 노드끼리만 동시에 옮길 수 있습니다");
						}

						// find min index
						for (int j = 0; j < parent.getChildCount(); j++) {
							if (parent.getChildAt(j) == rows[i]) {
								if (index < 0 || j < index) {
									index = j;
								}
								break;
							}
						}
					}

					// if index is 0 then can't go up
					if (index < 0 || index == 0)
						return;

					System.out.println("move row up");

					for (int i = 0; i < parent.getChildCount(); i++) {
						for (int j = 0; j < rows.length; j++) {
							if (parent.getChildAt(i) == rows[j]) {
								clsx.moveUp(rows[j]);
								break;
							}
						}
					}
					onCLSXChanged();
					treeView.select(rows);
				} catch (Exception e) {
					messageBox(e.getMessage());
				}

				super.widgetSelected(arg0);
			}
		});
		moveUp.setToolTipText("Move Up");

		// Move Down Icon
		ToolItem moveDown = new ToolItem(toolBar, SWT.NONE);
		moveDown.setImage(moveDownIcon);
		moveDown.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent arg0) {
				try {
					RowControl[] rows = treeView.getSelectedItems();
					if (rows.length == 0)
						throw new Exception("적어도 하나의 원소를 선택하세요");

					int index = -1;
					RowControl parent = (RowControl) rows[0].getParent();
					if (parent == null)
						return;

					for (int i = 0; i < rows.length; i++) {
						if (parent != rows[i].getParent()) {
							throw new Exception("부모가 같은 노드끼리만 동시에 옮길 수 있습니다");
						}

						// find max index
						for (int j = 0; j < parent.getChildCount(); j++) {
							if (parent.getChildAt(j) == rows[i]) {
								if (index < 0 || j > index) {
									index = j;
								}
								break;
							}
						}
					}

					// if index is terminal then can't go down
					if (index < 0 || index == parent.getChildCount() - 1)
						return;

					System.out.println("move row down");

					for (int i = 0; i < parent.getChildCount(); i++) {
						for (int j = 0; j < rows.length; j++) {
							if (parent.getChildAt(parent.getChildCount() - 1
									- i) == rows[j]) {
								clsx.moveDown(rows[j]);
								break;
							}
						}
					}
					onCLSXChanged();
					treeView.select(rows);
				} catch (Exception e) {
					messageBox(e.getMessage());
				}

				super.widgetSelected(arg0);
			}
		});
		moveDown.setToolTipText("Move Down");

		// Separating Toolbar area
		new ToolItem(toolBar, SWT.SEPARATOR);

		// Delete Icon
		ToolItem deleteItem = new ToolItem(toolBar, SWT.NONE);
		deleteItem.setImage(deleteIcon);
		deleteItem.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				deleteRow();
				super.widgetSelected(e);
			}
		});
		deleteItem.setToolTipText("Delete");

		KeyListener listener = new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				if (e.keyCode == SWT.DEL) {
					deleteRow();
				}
				super.keyPressed(e);
			}
		};
		treeView = new CLSXTreeView(composite_1, SWT.FILL);
		treeView.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4,
				2));
		treeView.setOnDSMChangeListener(this);
		treeView.addKeyListener(listener);

		tableView = new DSMTableView(sf, SWT.FILL);
		tableView.setOnDSMChangeListener(this);
		sf.setWeights(new int[] { 258, 329 });
		tableView.addKeyListener(listener);

		sf.addListener(SWT.Resize, new Listener() {
			@Override
			public void handleEvent(Event arg0) {
				sf.setWeights(new int[] { 287, Math.abs(sf.getSize().x - 287) });
			}
		});
	}
	
	// Sorting through ascending sort by alphabet
	private void doSort()
	{
		RowControl item = treeView.getSelectedItem();
		if(item == null) {
			messageBox("정렬할 그룹을 선택하세요");
			return;
		}
		else if(item.isLeaf()) {
			messageBox("그룹 노드만 지정할 수 있습니다");
			return;
		}
		
		try {
			clsx.sortMatrix((GroupControl) item);
			onCLSXChanged();
		} catch (Exception e) {
			messageBox("error!\n" + e.getMessage());
			return;
		}
	}

	// Ungrouping
	protected void doUngroup() {
		RowControl[] selected = treeView.getSelectedItems();
		if(selected == null || selected.length == 0) {
			messageBox("해제할 그룹을 선택하세요");
			return;
		}
		
		for(int i=0; i<selected.length; i++) {
			if (selected[i] == null || selected[i].isLeaf()) {
				messageBox("그룹만 선택해야 합니다");
				return;
			}
			else if(selected[i].getParent() == null) {
				messageBox("root노드를 고칠 수 없습니다");
				return;
			}
		}

		for(int i=0; i<selected.length; i++) {
			clsx.unGroup((GroupControl) selected[i]);
		}
		onCLSXChanged();
	}

	// Grouping
	protected void makeGroup() {
		RowControl[] rcSelected = treeView.getSelectedItems();
		if (rcSelected.length == 0) {
			messageBox("적어도 하나 이상의 원소를 선택해야 합니다");
			return;
		}

		// level check - root
		int level = rcSelected[0].getDepth();
		if (level == 0) {
			messageBox("Root를 변경할 수 없습니다");
			return;
		}

		// level check - is same depth?
		for (int i = 0; i < rcSelected.length; i++) {
			int depth = rcSelected[i].getDepth();
			if (level != depth) {
				messageBox("같은 레벨의 원소끼리만 그룹지을 수 있습니다");
				return;
			}
		}

		InputDialog dialog = new InputDialog(shell, "질문",
				"새 클러스터의 이름을 적으세요", "", null);
		int ret = dialog.open();
		if (ret == InputDialog.CANCEL)
			return;

		GroupControl newGroup = clsx.makeGroup(dialog.getValue());
		try {
			GroupControl parent = (GroupControl) rcSelected[0]
					.getParent();
			parent.insertGroupMember(newGroup, rcSelected[0]);
			for (int i = 0; i < rcSelected.length; i++) {
				parent.removeGroupMember(rcSelected[i]);
				newGroup.addGroupMember(rcSelected[i]);
				clsx.moveRowTo(rcSelected[i], rcSelected[0], false);
			}
		} catch (Exception e1) {
			messageBox("error!\n" + e1.toString());
			e1.printStackTrace();
		}
		onCLSXChanged();
	}

	// Add new row
	private void addRow() {
		InputDialog dialog = new InputDialog(shell, "새 행", "새 행의 이름을 입력하세요",
				"", null);
		int ret = dialog.open();
		if (ret == InputDialog.OK) {
			String value = dialog.getValue();
			if (value == null || value.equals("")) {
				messageBox("잘못된 이름입니다");
				return;
			}

			System.out.println(String.format("make row %s", value));
			RowControl rc = clsx.makeRow(value);
			clsx.addRow(rc);

			dsmChanged = true;
			onCLSXChanged();
		}
	}

	// Changing name
	private void rename() {
		RowControl rc = treeView.getSelectedItem();
		if (rc == null) {
			messageBox("이름을 바꿀 것을 선택하세요");
			return;
		}

		InputDialog dialog = new InputDialog(shell, "Rename", "바꿀 이름을 입력하세요", rc.getName(), null);
		int ret = dialog.open();
		if (ret == InputDialog.OK) {
			System.out.println(String.format("change name to %s",
					dialog.getValue()));
			rc.setName(dialog.getValue());
			
			if(rc.isLeaf())
				dsmChanged = true;
			onCLSXChanged();
		}
	}

	// Refreshing Window
	private void refresh() {
		tableView.refresh(clsx, arrayList);
		treeView.refresh(clsx);
		refreshTitle();
	}

	// Saving DSM file
	private boolean saveDSM() {
		if (dsmFile.getCurrentFile() == null)
			return saveDSM_as();

		try {
			dsmFile.save(clsx);
		} catch (Exception e) {
			messageBox("DSM파일 저장하는 중 오류");
			return false;
		}

		dsmChanged = false;
		return true;
	}

	// Save DSM file as new name
	private boolean saveDSM_as() {
		FileDialog dialog = new FileDialog(shell, SWT.SAVE);
		dialog.setOverwrite(true);
		dialog.setFilterNames(new String[] { "DSM files(*.dsm)",
				"All files(*.*)" });
		dialog.setFilterExtensions(new String[] { "*.dsm", "*.*" });

		String name = dialog.open();
		if (name == null)
			return false;

		try {
			dsmFile.saveAs(clsx, new File(name));
		} catch (Exception e) {
			messageBox("DSM파일 저장하는 중 오류");
			return false;
		}

		dsmChanged = false;
		return true;
	}

	// Saving CLSX file
	private boolean saveCLSX() {
		if (clsxFile.getCurrentFile() == null)
			return saveCLSX_as();

		try {
			clsxFile.save(clsx);
		} catch (Exception e) {
			messageBox("CLSX파일 저장하는 중 오류");
			return false;
		}

		clsxChanged = false;
		return true;
	}

	// Saving CLSX file as new name
	private boolean saveCLSX_as() {
		FileDialog dialog = new FileDialog(shell, SWT.SAVE);
		dialog.setOverwrite(true);
		dialog.setFilterNames(new String[] { "Clustering files(*.clsx)",
				"All files(*.*)" });
		dialog.setFilterExtensions(new String[] { "*.clsx", "*.*" });

		String name = dialog.open();
		if (name == null)
			return false;

		try {
			clsxFile.saveAs(clsx, new File(name));
		} catch (Exception e) {
			messageBox("CLSX파일 저장하는 중 오류");
			return false;
		}

		clsxChanged = false;
		return true;
	}

	// New DSM file
	private void newDSM() {
		newCLSX();

		if (checkDSMChange() == false)
			return;

		dsmFile.newFile();
		dsmChanged = false;
		clsx = new CLSXTreeModel();
		tltmLoadClu.setEnabled(false);
		fileLoadClustering.setEnabled(false);
		refresh();
	}

	// New CLSX file
	private void newCLSX() {
		if (checkCLSXChange() == false) {
			return;
		}

		clsxFile.newFile();
		clsxChanged = false;
		clsx.resetTree();
		refresh();
	}

	// If CLSX file is changed then ask saving
	private boolean checkCLSXChange() {
		if (clsxChanged) {
			MessageBox msg = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES
					| SWT.NO | SWT.CANCEL);
			msg.setText(WINDOW_NAME);
			msg.setMessage("Tree가 변경되었습니다. 저장하시겠습니까?");
			int ret = msg.open();

			if (ret == SWT.CANCEL)
				return false;

			if (ret == SWT.NO)
				return true;

			if (!saveCLSX())
				return false;
		}

		return true;
	}

	// If DSM file is changed then ask saving
	private boolean checkDSMChange() {
		if (dsmChanged) {
			MessageBox msg = new MessageBox(shell, SWT.ICON_QUESTION | SWT.YES
					| SWT.NO | SWT.CANCEL);
			msg.setText(WINDOW_NAME);
			msg.setMessage("DSM이 변경되었습니다. 저장하시겠습니까?");
			int ret = msg.open();

			System.out.println("ret = " + ret);
			if (ret == SWT.CANCEL)
				return false;

			if (ret == SWT.NO)
				return true;

			if (!saveDSM())
				return false;
		}

		return true;
	}

	// Deleting Row
	private void deleteRow() {
		RowControl[] list = treeView.getSelectedItems();
		if (list.length == 0) {
			messageBox("삭제할 행을 선택하세요");
			return;
		}

		for (RowControl rc : list) {
			if (rc.isLeaf() == false) {
				messageBox("Leaf노드만 삭제 가능합니다");
				return;
			}
		}

		for (RowControl rc : list) {
			for (int i = 0; i < clsx.getDSM().getSize(); i++) {
				// remove dependency to it
				clsx.getDSM().getRow(i).removeDependency(rc);
			}
			// remove row
			clsx.removeRow(rc);
		}

		dsmChanged = true;
		onCLSXChanged();

		RowControl rc = clsx.getDSM().getRow(tableView.getSelectedIndex());
		treeView.select(rc);
	}

	// Subclass for File Open
	class OpenFileListener implements SelectionListener {

		int selectionNum = 0;

		@Override
		public void widgetDefaultSelected(SelectionEvent arg0) {
		}

		@Override
		public void widgetSelected(SelectionEvent arg0) {
			FileDialog dialog = new FileDialog(shell);

			// Filter
			// If selectionNum is 0 then CLSX file save
			// Or if selectionNum is 1 then DSM file save
			if (selectionNum == 0) {
				if (checkCLSXChange() == false)
					return;
				dialog.setFilterNames(new String[] {
						"Clustering files(*.clsx)", "All files(*.*)" });
				dialog.setFilterExtensions(new String[] { "*.clsx", "*.*" });			
			} else if (selectionNum == 1) {
				if (checkCLSXChange() == false || checkDSMChange() == false)
					return;
				dialog.setFilterNames(new String[] { "DSM files(*.dsm)",
						"All files(*.*)" });
				dialog.setFilterExtensions(new String[] { "*.dsm", "*.*" });
			}

			// Get file
			String fileName = dialog.open();
			if (fileName == null)
				return;
			System.out.println("open " + fileName);

			// For backup save state, on error, it will be backup
			boolean bkup_clsx = clsxChanged;
			boolean bkup_dsm = dsmChanged;
			clsxChanged = false;
			dsmChanged = false;

			try {
				CLSXControl clsx;

				if (selectionNum == 0) {
					newCLSX();
					clsx = clsxFile.open(new File(fileName));
				} else {
					newDSM();
					clsx = dsmFile.open(new File(fileName));
					clsxFile = new CLSXFile(clsx.getDSM());
				}

				MainFrame.this.clsx = clsx;
				tltmLoadClu.setEnabled(true);
				fileLoadClustering.setEnabled(true);
			} catch (Exception e) {
				clsxChanged = bkup_clsx;
				dsmChanged = bkup_dsm;
				messageBox("Cannot open file!\n" + e.getMessage());
				return;
			}

			refresh();
		}

		public OpenFileListener(int selectionNum) {
			this.selectionNum = selectionNum;
		}
	}

	// Refreshing Title
	public void refreshTitle() {

		MainFrame.this.clsx = clsx;
		File dsmCurrent = dsmFile.getCurrentFile();
		String dsmName = " - "
				+ (dsmCurrent == null ? "새 DSM" : dsmCurrent.getName());
		dsmName += dsmChanged ? "*" : "";
		File clsxCurrent = clsxFile.getCurrentFile();
		String clsxName = " - "
				+ (clsxCurrent == null ? "새 CLSX" : clsxCurrent.getName());
		clsxName += clsxChanged ? "*" : "";

		shell.setText(WINDOW_NAME);
		shell.setText(shell.getText() + dsmName);
		shell.setText(shell.getText() + clsxName);
	}

	@Override
	public void onDSMChanged() {
		this.dsmChanged = true;
		tableView.refresh(clsx, arrayList);
		refreshTitle();
	}

	@Override
	public void onCLSXChanged() {
		this.clsxChanged = true;
		refresh();
	}

	@Override
	public void onSelectionChanged(RowControl row) {
		if (row == null)
			return;

		System.out.println("onselectionchanged " + row.getName());

		// table
		if (row.isLeaf()) {
			for (int i = 0; i < clsx.getDSM().getSize(); i++) {
				if (row == clsx.getDSM().getRow(i)) {
					tableView.select(i);
					break;
				}
			}
		} else {
			tableView.select(-1);
		}

		// tree
		treeView.select(row);
	}

	private void messageBox(String str) {
		MessageBox msg = new MessageBox(shell);
		msg.setText("메세지");
		msg.setMessage(str);
		msg.open();
	}

	@Override
	public void onExpandChanged(List<RowControl> list) {
		arrayList = list;
		tableView.refresh(clsx, list);
	}

	@Override
	public void onRequestDelete() {
		deleteRow();
	}

	@Override
	public void onRequestRename() {
		rename();
	}

	@Override
	public void onRequestGroup() {
		makeGroup();
	}

	@Override
	public void onRequestUngroup() {
		doUngroup();
	}

	@Override
	public void onRequestSort() {
		doSort();
	}
}